"""
Servlets to add different kinds of patient records to the datastore.

Convention in this file is to have one class per screen, with the
class get() method generating the screen and the post() method
handling the data received from the user.

TODO: we can probably merge the two add_patient_id.html and
add_proc.html files

TODO: move validation into the Field class, letting it validate dates
and a few other things we use a lot.
"""

_author_ = 'pablo@google.com'

import datetime
import logging
import os

from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext import db

import data_model
from form_util import StringToDate
from form_util import Field

####################################################################
def ValidateInputs(fields):
  """If inputs are valid, return a dict of name:value, otherwise,
  mark up errors in error_message fields and return None.
  """
  
  values = {}
  valid = True
  for field in fields:
    valid &= field.Validate()
    values[field.name] = field.value
  if not valid:
    return None
  return values

####################################################################
class AddPatientId(webapp.RequestHandler):
  """This is the initial patient information screen, with basic id."""

  ###################################################
  def __init__(self, pid=None):
    self.pid = pid
    self.title = 'Patient Information'
    self.fields = [
      Field('given_name', 'Patient given name', required=True),
      Field('family_name', 'Patient family name', required=True),
      Field('gender', 'Gender', required=True, type='radio',
            value_choices=['Male', 'Female']),
      Field('dob', 'Date of birth', help_text='In YYYY-MM-DD format',
            required=True, data_type='date'),
      Field('voter_id', 'Voter ID number'),
      Field('mobile_number', 'Mobile phone number'),
      Field('visit_location', 'Location of current visit',
            help_text='Example: USNS Comfort'),
      Field('living_location', 'Where is the patient living now?',
            help_text='Example: Cite Aux Cayes'),
      Field('notes', 'Notes', type='textarea',
            extra_params=['rows="3"', 'cols="60"']),        
      ]
    """
    # Awkwardly copy the datastore values into the fields
    if pid:
      pid_record = db.get(pid)
      for field in self.fields:
        field.__dict__['value'] = pid_record.__dict__[field.name]
    """ 
  ###################################################
  def get(self, fields=None):
    """Generate form to add patient id.

    If the user gives us erroneous input, we may get called again,
    this time with 'fields' specified, which we'll expect to contain
    some already filled-in values.
    TODO(pablo): allow passing in an existing datastore PID to be edited.
    """

    template_values = {
      'errors': fields is not None,
      'title': self.title,
      'fields': fields or self.fields,
    }
    path = os.path.join(os.path.dirname(__file__),
                        'templates/add_patient_id.html')
    self.response.out.write(template.render(path, template_values))
     
  ###################################################
  def post(self):
    """Process form to add patient id"""

    # Copy the field values
    for field in self.fields:
      field.value = self.request.get(field.name)

    # If we failed to validate the input, issue another get
    values = ValidateInputs(self.fields)
    if not values:
      self.get(fields=self.fields)
      return None

    # If it's all good, create a PID object and store it
    logging.info('Writing PID datastore record')
    pid = data_model.PID(given_name=values['given_name'],
                         family_name=values['family_name'],
                         gender=values['gender'],
                         dob=StringToDate(values['dob']),
                         voter_id=values['voter_id'],
                         mobile_number=values['mobile_number'] or 'none',
                         visit_location=values['visit_location'],
                         living_location=values['living_location'],
                         notes=values['notes'])
    pid.put()
    self.pid = pid.key()

    # And see which button was pushed to figure out what we do next
    if self.request.get('add_proc'):
      next_page = 'add_proc'
    elif self.request.get('add_problem'):
      next_page = 'add_problem'
    elif self.request.get('add_med'):
      next_page = 'add_med'
    elif  self.request.get('add_allergy'):
      next_page = 'add_allergy'
    elif self.request.get('add_test'):
      next_page = 'add_test'
    else:
      next_page = 'add_proc'  # the default
    self.redirect('/%s?pid=%s' % (next_page, self.pid))


####################################################################
class AddProcedure(webapp.RequestHandler):
  """Screen to add surgeries and procedures."""

  ###################################################
  def __init__(self):
    self.pid = None
    self.title = 'Surgery or Procedure'
    self.fields = [
      Field('proc_name', 'Name of surgery/procedure',
            help_text='Example: Left leg below-the-knee amputation',
            required=True),
      Field('date', 'Date', help_text='In YYYY-MM-DD format',
            required=True, data_type='date',
            value=datetime.date.today()),
      Field('notes', 'Notes', type='textarea',
            extra_params=['rows="3"', 'cols="60"']),        
      ]
                     
  ###################################################
  def get(self, fields=None):
    """Generate form to add procedure or surgery.

    If the user gives us erroneous input, we may get called again,
    this time with 'fields' specified, which we'll expect to contain
    some already filled-in values.
    """
    self.pid = self.request.get('pid')

    template_values = {
      'pid': self.pid,
      'errors': fields is not None,
      'title': self.title,
      'fields': fields or self.fields,
    }
    path = os.path.join(os.path.dirname(__file__),
                        'templates/add_proc.html')
    self.response.out.write(template.render(path, template_values))

  ###################################################
  def post(self):
    """Process form to add procedure"""

    self.pid = self.request.get('pid')
    # Copy the field values
    for field in self.fields:
      field.value = self.request.get(field.name)

    # If we failed to validate the input, issue another get
    values = ValidateInputs(self.fields)
    if not values:
      self.get(fields=self.fields)
      return None

    # If it's all good, create a Procedure object and store it
    logging.info('Writing Procedure datastore record')
    proc = data_model.Procedure(pid=db.get(self.pid),
                                proc_name=values['proc_name'],
                                date=StringToDate(values['date']),
                                notes=values['notes'])
    proc.put()
    
    # See which button was pushed
    if self.request.get('add_proc'):
      next_page = 'add_proc'
    elif self.request.get('add_problem'):
      next_page = 'add_problem'
    elif self.request.get('add_med'):
      next_page = 'add_med'
    elif  self.request.get('add_allergy'):
      next_page = 'add_allergy'
    elif self.request.get('add_test'):
      next_page = 'add_test'
    else:
      next_page = 'add_problem'  # the default
    self.redirect('/%s?pid=%s' % (next_page, self.pid))
